#pragma once
#include "net.hpp"

// 之前: void onRpcReq(const jsonrpc::BaseConnection::ptr& conn, jsonrpc::BaseMessage::ptr& msg)
// 现在: void onRpcReq(const jsonrpc::BaseConnection::ptr& conn, jsonrpc::RpcRequest::ptr& msg)
// 希望在外部设置回调函数的时候, 直接传递指定类型的消息 --> 导致消息类型不一致 --> 哈希表不能存不同的类型
// 考虑使用模板函数

// 1.哈希表中存父类指针(统一类型), 调用回调函数的时候(子类进行类型转换), 在调用对应的回调函数
// 2.效果: 在外直接传消息类型,去使用
namespace jsonrpc
{
    class Callback
    {
    public:
        using ptr = std::shared_ptr<Callback>;
        virtual void onMessage(const BaseConnection::ptr &conn, BaseMessage::ptr &msg) = 0;
    };

    template <typename T>
    class CallbackT : public Callback
    {
    public:
        using ptr = std::shared_ptr<CallbackT<T>>;
        using MessageCallback = std::function<void(const BaseConnection::ptr &conn, std::shared_ptr<T> &msg)>;
        // 保存对应的回调函数
        CallbackT(const MessageCallback &handler) : _handler(handler) {}
        // 子类做类型转换, 然后调用回调函数
        void onMessage(const BaseConnection::ptr &conn, BaseMessage::ptr &msg) override
        {
            auto type_msg = std::dynamic_pointer_cast<T>(msg);
            _handler(conn, type_msg);
        }

    private:
        MessageCallback _handler;
    };

    class Dispatcher
    {
    public:
        using ptr = std::shared_ptr<Dispatcher>;

        // 接口1 : 给客户端 or 服务端提供的 -- 根据类型 注册 对应回调函数
        // 说明 : 这里T传过来的是消息类型, 我们根据消息类型, 生成对应的函数类型
        template <typename T>
        void registerHandler(MType mtype, const typename CallbackT<T>::MessageCallback &handler)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto cb = std::make_shared<CallbackT<T>>(handler);
            _handlers.insert(std::make_pair(mtype, cb));
        }
        // 接口2 :消息触发就调用该函数 -- 会根据类型去调用对应函数
        void onMessage(const BaseConnection::ptr &conn, BaseMessage::ptr &msg)
        {
            // 找到消息类型对应的业务处理函数，进行调用即可
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _handlers.find(msg->rMType());
            if (it == _handlers.end())
            {
                ELOG("没有找到指定类型的处理回调");
                conn->shutdown();
                return;
            }
            // 调用对应回调函数
            it->second->onMessage(conn, msg);
        }
    private:
        std::mutex _mutex;
        std::unordered_map<MType, Callback::ptr> _handlers;
    };
}